/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
define(["require", "exports", "../utils/convert", "../utils/codeAction", "../utils/workspaceEdit"], function (require, exports, convert_1, codeAction_1, workspaceEdit_1) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    class ApplyCodeActionCommand {
        constructor(client) {
            this.client = client;
            this.id = ApplyCodeActionCommand.ID;
        }
        execute(actions) {
            return __awaiter(this, void 0, void 0, function* () {
                return codeAction_1.applyCodeActionCommands(this.client, actions);
            });
        }
    }
    ApplyCodeActionCommand.ID = '_typescript.applyCodeActionCommand';
    class ApplyFixAllCodeAction {
        constructor(client, vscode) {
            this.client = client;
            this.vscode = vscode;
            this.id = ApplyFixAllCodeAction.ID;
        }
        execute(file, tsAction) {
            return __awaiter(this, void 0, void 0, function* () {
                if (!tsAction.fixId) {
                    return;
                }
                const args = {
                    scope: {
                        type: 'file',
                        args: { file }
                    },
                    fixId: tsAction.fixId
                };
                try {
                    const combinedCodeFixesResponse = yield this.client.execute('getCombinedCodeFix', args);
                    if (!combinedCodeFixesResponse.body) {
                        return;
                    }
                    const edit = workspaceEdit_1.createWorkspaceEditFromFileCodeEdits(this.client, combinedCodeFixesResponse.body.changes, this.vscode);
                    yield this.vscode.workspace.applyEdit(edit);
                    if (combinedCodeFixesResponse.command) {
                        yield this.vscode.commands.executeCommand(ApplyCodeActionCommand.ID, combinedCodeFixesResponse.command);
                    }
                }
                catch (_a) {
                    // noop
                }
            });
        }
    }
    ApplyFixAllCodeAction.ID = '_typescript.applyFixAllCodeAction';
    class SupportedCodeActionProvider {
        constructor(client) {
            this.client = client;
        }
        getFixableDiagnosticsForContext(context) {
            return __awaiter(this, void 0, void 0, function* () {
                const supportedActions = yield this.supportedCodeActions;
                return context.diagnostics.filter((diagnostic) => supportedActions.has(+diagnostic.code));
            });
        }
        get supportedCodeActions() {
            if (!this._supportedCodeActions) {
                this._supportedCodeActions = this.client.execute('getSupportedCodeFixes', null, undefined)
                    .then(response => response.body || [])
                    .then(codes => codes.map((code) => +code).filter((code) => !isNaN(code)))
                    .then(codes => new Set(codes));
            }
            return this._supportedCodeActions;
        }
    }
    class TypeScriptQuickFixProvider {
        constructor(client, formattingConfigurationManager, commandManager, diagnosticsManager, vscode) {
            this.client = client;
            this.formattingConfigurationManager = formattingConfigurationManager;
            this.diagnosticsManager = diagnosticsManager;
            this.vscode = vscode;
            commandManager.register(new ApplyCodeActionCommand(client));
            commandManager.register(new ApplyFixAllCodeAction(client, this.vscode));
            this.supportedCodeActionProvider = new SupportedCodeActionProvider(client);
        }
        provideCodeActions(document, _range, context, token) {
            return __awaiter(this, void 0, void 0, function* () {
                if (!this.client.apiVersion.has213Features()) {
                    return [];
                }
                const file = this.client.normalizePath(document.uri);
                if (!file) {
                    return [];
                }
                const fixableDiagnostics = yield this.supportedCodeActionProvider.getFixableDiagnosticsForContext(context);
                if (!fixableDiagnostics.length) {
                    return [];
                }
                yield this.formattingConfigurationManager.ensureFormatOptionsForDocument(document, token);
                const results = [];
                for (const diagnostic of fixableDiagnostics) {
                    results.push(...yield this.getFixesForDiagnostic(document, file, diagnostic, token));
                }
                return results;
            });
        }
        getFixesForDiagnostic(document, file, diagnostic, token) {
            return __awaiter(this, void 0, void 0, function* () {
                const args = Object.assign({}, convert_1.vsRangeToTsFileRange(file, diagnostic.range), { errorCodes: [+diagnostic.code] });
                const codeFixesResponse = yield this.client.execute('getCodeFixes', args, token);
                if (codeFixesResponse.body) {
                    const results = [];
                    for (const tsCodeFix of codeFixesResponse.body) {
                        results.push(...yield this.getAllFixesForTsCodeAction(document, file, diagnostic, tsCodeFix));
                    }
                    return results;
                }
                return [];
            });
        }
        getAllFixesForTsCodeAction(document, file, diagnostic, tsAction) {
            return __awaiter(this, void 0, void 0, function* () {
                const singleFix = this.getSingleFixForTsCodeAction(diagnostic, tsAction);
                const fixAll = yield this.getFixAllForTsCodeAction(document, file, diagnostic, tsAction);
                return fixAll ? [singleFix, fixAll] : [singleFix];
            });
        }
        getSingleFixForTsCodeAction(diagnostic, tsAction) {
            const codeAction = new this.vscode.CodeAction(tsAction.description, this.vscode.CodeActionKind.QuickFix);
            codeAction.edit = codeAction_1.getEditForCodeAction(this.client, tsAction, this.vscode);
            codeAction.diagnostics = [diagnostic];
            if (tsAction.commands) {
                codeAction.command = {
                    command: ApplyCodeActionCommand.ID,
                    arguments: [tsAction],
                    title: tsAction.description
                };
            }
            return codeAction;
        }
        getFixAllForTsCodeAction(document, file, diagnostic, tsAction) {
            return __awaiter(this, void 0, void 0, function* () {
                if (!tsAction.fixId || !this.client.apiVersion.has270Features()) {
                    return undefined;
                }
                // Make sure there are multiple diagnostics of the same type in the file
                if (!this.diagnosticsManager.getDiagnostics(document.uri).some(x => x.code === diagnostic.code && x !== diagnostic)) {
                    return;
                }
                const action = new this.vscode.CodeAction('{' + tsAction.description + '} (Fix all in file)', this.vscode.CodeActionKind.QuickFix);
                action.diagnostics = [diagnostic];
                action.command = {
                    command: ApplyFixAllCodeAction.ID,
                    arguments: [file, tsAction],
                    title: ''
                };
                return action;
            });
        }
    }
    exports.default = TypeScriptQuickFixProvider;
});
